
/****************************************************************************/
/*Copyright (c) 2011, Florent DEVILLE.                                      */
/*All rights reserved.                                                      */
/*                                                                          */
/*Redistribution and use in source and binary forms, with or without        */
/*modification, are permitted provided that the following conditions        */
/*are met:                                                                  */
/*                                                                          */
/* - Redistributions of source code must retain the above copyright         */
/*notice, this list of conditions and the following disclaimer.             */
/* - Redistributions in binary form must reproduce the above                */
/*copyright notice, this list of conditions and the following               */
/*disclaimer in the documentation and/or other materials provided           */
/*with the distribution.                                                    */
/* - The names of its contributors cannot be used to endorse or promote     */
/*products derived from this software without specific prior written        */
/*permission.                                                               */
/* - The source code cannot be used for commercial purposes without         */ 
/*its contributors' permission.                                             */
/*                                                                          */
/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/*"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/*LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         */
/*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            */
/*COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       */
/*INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,      */
/*BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          */
/*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER          */
/*CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT        */
/*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN         */
/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/*POSSIBILITY OF SUCH DAMAGE.                                               */
/****************************************************************************/

#include "GeoMesh.h"

#include "Scene.h"
#include "GeoVertex.h"
#include "OGLVisu.h"
#include <QGLWidget>

//constructor
GeoMesh::GeoMesh() :Geometry(GT_MESH), _triangleDrawVertexID(-1), _triangleDrawTriangleCount(-1)
{
	_rotationMarkRadius = 0.f;
	_translateMark = CVector3f(0, 0, 0);
	memset(_aabb, 0, 6* sizeof(float));
}

//destructor
GeoMesh::~GeoMesh()
{}

//determine if the point v is a point of the geometry object
bool GeoMesh::isGeometry(const CVector3f& v)const
{
	//calculate the world matrix of the primitive
	CMatrix transform = getWorldMatrix();

	//get V in local coordinate of the mesh
	CVector3f localV = v * transform.inverse();

	const float offset = 0.1f;

	//check if outside the bounding box
	if (localV.x < _aabb[0] || localV.x > _aabb[1] ||	//0 : minX, 1 : maxX
		localV.y < _aabb[2] || localV.y > _aabb[3] ||	//2 : minY, 3 : maxY
		localV.z < _aabb[4] || localV.z > _aabb[5])		//4 : minZ, 5 : maxZ
		return false;

	return true;
}

//pre render the object
void GeoMesh::preRender()
{
	//store current matrix
	glPushMatrix();

	//apply translation
	glTranslatef(_translate.x, _translate.y, _translate.z);
	
	//apply rotations
	glRotatef(_rotate.x, 1, 0, 0);

	glRotatef(_rotate.y, 0, 1, 0);

	glRotatef(_rotate.z, 0, 0, 1);

	//apply scale
	glScalef(_scale.x, _scale.y, _scale.z);

	//apply material
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, _material.getAmbient());
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, _material.getDiffuse());
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, _material.getSpecular());
	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, _material.getShininess());
}

//render the object
void GeoMesh::Render()
{
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, (GLuint)_material.getTexture());

	//get the number of triangles
	if (_indexBuffer.empty()) return;
	int nbTriangles = _indexBuffer.size() / 3;

	//loop through the triangles to draw them
	int indexBufferCount = 0;
	for(int i = 0; i < nbTriangles; i++)
	{

		CVector3f n = _normalPerTriangleBuffer[i];
		CVector3f v1 = _vertexBuffer[_indexBuffer[indexBufferCount]]._position;
		CVector3f v2 = _vertexBuffer[_indexBuffer[indexBufferCount+1]]._position;
		CVector3f v3 = _vertexBuffer[_indexBuffer[indexBufferCount+2]]._position;

		CVector3f t1 = _uvMapBuffer[indexBufferCount];
		CVector3f t2 = _uvMapBuffer[indexBufferCount+1];
		CVector3f t3 = _uvMapBuffer[indexBufferCount+2];

		glBegin(GL_TRIANGLES);
			glNormal3f(n.x, n.y, n.z);
			glTexCoord2f(t1.x, t1.y); glVertex3f(v1.x, v1.y, v1.z);
			glTexCoord2f(t2.x, t2.y); glVertex3f(v2.x, v2.y, v2.z);
			glTexCoord2f(t3.x, t3.y); glVertex3f(v3.x, v3.y, v3.z);
		glEnd();

		indexBufferCount += 3;
	}
	
	//disable texturing
	glDisable(GL_TEXTURE_2D);

	//draw the selected triangle
	drawSelectedTriangle();
}

//post render function
void GeoMesh::postRender()
{
	//if the sphere is selected, draw the surrounding box and the translation mark
	if(_selected)
	{
		float w = _aabb[1] - _aabb[0];
		float h = _aabb[3] - _aabb[2];
		float d = _aabb[5] - _aabb[4];

		float x = _aabb[1] + _aabb[0];
		float y = _aabb[3] + _aabb[2];
		float z = _aabb[5] + _aabb[4];
		glTranslatef(x/2.f, y/2.f, z/2.f);
		VISU.drawSelectionBox(w, h, d);
	}

	glPopMatrix();

}

//create a cube mesh
void GeoMesh::createCube(int size)
{
	//calculate size
	float s = size / 2.f;

	//front face
	CVector3f n0(0, 0, 1);
	meshVertex v0(CVector3f(-s, s, s), n0);
	meshVertex v1(CVector3f(s, s, s), n0);
	meshVertex v2(CVector3f(s, -s, s), n0);
	meshVertex v3(CVector3f(-s, -s, s), n0);

	//top face using v0 and v1
	meshVertex v4(CVector3f(s, s, -s), n0);
	meshVertex v5(CVector3f(-s, s, -s), n0);

	//right face using v2, V1 and v4
	meshVertex v6(CVector3f(s, -s, -s), n0);

	//left face using V3, V0 and v5
	meshVertex v7(CVector3f(-s, -s, -s), n0);

	//bottom face using 3, 2, 6, 7
	//back face using 7, 5, 4, 6

	//create the geovertex
	GeoVertex* newV = 0;

	_vertexBuffer.push_back(v0);
	newV = SCENE.createVertex();
	newV->setInfo(this, 0, v0._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v1);
	newV = SCENE.createVertex();
	newV->setInfo(this, 1, v1._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v2);
	newV = SCENE.createVertex();
	newV->setInfo(this, 2, v2._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v3);
	newV = SCENE.createVertex();
	newV->setInfo(this, 3, v3._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v4);
	newV = SCENE.createVertex();
	newV->setInfo(this, 4, v4._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v5);
	newV = SCENE.createVertex();
	newV->setInfo(this, 5, v5._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v6);
	newV = SCENE.createVertex();
	newV->setInfo(this, 6, v6._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v7);
	newV = SCENE.createVertex();
	newV->setInfo(this, 7, v7._position);
	_geoVertexBuffer.push_back(newV);

	//create the triangles
	//front
	_indexBuffer.push_back(0);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_indexBuffer.push_back(2);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_indexBuffer.push_back(1);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, 0, 1));
	_indexBuffer.push_back(0);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_indexBuffer.push_back(3);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_indexBuffer.push_back(2);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, 0, 1));

	//right
	_indexBuffer.push_back(1);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_indexBuffer.push_back(2);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_indexBuffer.push_back(6);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(1, 0, 0));
	_indexBuffer.push_back(1);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_indexBuffer.push_back(6);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_indexBuffer.push_back(4);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(1, 0, 0));

	//left
	_indexBuffer.push_back(0);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_indexBuffer.push_back(7);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_indexBuffer.push_back(3);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(-1, 0, 0));
	_indexBuffer.push_back(0);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_indexBuffer.push_back(5);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_indexBuffer.push_back(7);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(-1, 0, 0));

	//back
	_indexBuffer.push_back(5);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_indexBuffer.push_back(4);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_indexBuffer.push_back(6);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, 0, -1));
	_indexBuffer.push_back(5);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_indexBuffer.push_back(6);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_indexBuffer.push_back(7);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, 0, -1));

	//top
	_indexBuffer.push_back(0);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_indexBuffer.push_back(1);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_indexBuffer.push_back(5);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, 1, 0));
	_indexBuffer.push_back(1);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_indexBuffer.push_back(4);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_indexBuffer.push_back(5);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, 1, 0));

	//bottom
	_indexBuffer.push_back(3);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_indexBuffer.push_back(7);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_indexBuffer.push_back(2);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, -1, 0));
	_indexBuffer.push_back(7);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_indexBuffer.push_back(6);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_indexBuffer.push_back(2);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, -1, 0));

	calculateAABB();

	
	//_material.setTexture("C:\\Users\\f.devillechabrol\\Desktop\\sdlgl_06_textures\\stainedglass05.jpg");
}

void GeoMesh::createPlan(int size)
{
	//calculate size
	float s = size / 2.f;

	CVector3f n0(0, 0, 1);
	meshVertex v0(CVector3f(-s, s, 0), n0);
	meshVertex v1(CVector3f(s, s, 0), n0);
	meshVertex v2(CVector3f(s, -s, 0), n0);
	meshVertex v3(CVector3f(-s, -s, 0), n0);

	GeoVertex* newV = 0;

	_vertexBuffer.push_back(v0);
	newV = SCENE.createVertex();
	newV->setInfo(this, 0, v0._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v1);
	newV = SCENE.createVertex();
	newV->setInfo(this, 1, v1._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v2);
	newV = SCENE.createVertex();
	newV->setInfo(this, 2, v2._position);
	_geoVertexBuffer.push_back(newV);

	_vertexBuffer.push_back(v3);
	newV = SCENE.createVertex();
	newV->setInfo(this, 3, v3._position);
	_geoVertexBuffer.push_back(newV);

	_indexBuffer.push_back(0);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_indexBuffer.push_back(2);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_indexBuffer.push_back(1);
	_uvMapBuffer.push_back(CVector3f(1, 0, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, 0, 1));
	_indexBuffer.push_back(2);
	_uvMapBuffer.push_back(CVector3f(1, 1, 0));
	_indexBuffer.push_back(0);
	_uvMapBuffer.push_back(CVector3f(0, 0, 0));
	_indexBuffer.push_back(3);
	_uvMapBuffer.push_back(CVector3f(0, 1, 0));
	_normalPerTriangleBuffer.push_back(CVector3f(0, 0, 1));

	calculateAABB();
}

//set the position of a vertex
void GeoMesh::setVertexPosition(int vertexIndex, const CVector3f& newPos)
{
	if (vertexIndex >= _vertexBuffer.size()) return;
	_vertexBuffer[vertexIndex]._position = newPos;
}

//get the position of a vertex in local coordinate
CVector3f GeoMesh::getVertexPosition(int vertexIndex)
{
	if (vertexIndex >= _vertexBuffer.size()) return CVector3f();
	return _vertexBuffer[vertexIndex]._position;
}

//calculate the axis aligned bounding box
void GeoMesh::calculateAABB()
{
	bool first = true;
	/*_aabb[0] = _aabb[1] = _vertexBuffer.front()._position.x;
	_aabb[2] = _aabb[3] = _vertexBuffer.front()._position.y;
	_aabb[4] = _aabb[5] = _vertexBuffer.front()._position.z;*/

	for(vector<meshVertex>::iterator i = _vertexBuffer.begin() + 1; i != _vertexBuffer.end(); i++)
	{
		if (i->_normal.norme2() == 0) continue;

		if (first)
		{
			_aabb[0] = _aabb[1] = i->_position.x;
			_aabb[2] = _aabb[3] = i->_position.y;
			_aabb[4] = _aabb[5] = i->_position.z;
			first = false;
			continue;
		}

		if (_aabb[0] > i->_position.x) _aabb[0] = i->_position.x;
		if (_aabb[1] < i->_position.x) _aabb[1] = i->_position.x;

		if (_aabb[2] > i->_position.y) _aabb[2] = i->_position.y;
		if (_aabb[3] < i->_position.y) _aabb[3] = i->_position.y;

		if (_aabb[4] > i->_position.z) _aabb[4] = i->_position.z;
		if (_aabb[5] < i->_position.z) _aabb[5] = i->_position.z;
	}

	const float offset = 0.1f;
	if (_aabb[0] == _aabb[1])
	{
		_aabb[0] -= offset;
		_aabb[1] += offset;
	}
	if (_aabb[2] == _aabb[3])
	{
		_aabb[2] -= offset;
		_aabb[3] += offset;
	}
	if (_aabb[4] == _aabb[5])
	{
		_aabb[4] -= offset;
		_aabb[5] += offset;
	}

	_translateMark = CVector3f(0, _aabb[3] + 0.2f, 0);
	_rotationMarkRadius = _aabb[1] - _aabb[0] + 0.2f;

	_aabb[0] -= offset;
	_aabb[2] -= offset;
	_aabb[4] -= offset;
	_aabb[1] += offset;
	_aabb[3] += offset;
	_aabb[5] += offset;
}

//add a vertex on the line v1;v2
bool GeoMesh::addVertex(int v1, int v2)
{
	//check if the vertices exist
	if (v1 < 0 || v1 >= _vertexBuffer.size() || v2 < 0 || v2 >= _vertexBuffer.size()) return false;
	
	int size = _indexBuffer.size();
	int newIndex = -1;
	for(int triangleID = 0; triangleID < size; triangleID+= 3)
	{
		//if the edge is not in the triangle, go to the next triangle
		if (!((_indexBuffer[triangleID] == v1 && _indexBuffer[triangleID+1] == v2)||
			(_indexBuffer[triangleID] == v2 && _indexBuffer[triangleID+1] == v1) ||
			(_indexBuffer[triangleID] == v1 && _indexBuffer[triangleID+2] == v2) ||
			(_indexBuffer[triangleID] == v2 && _indexBuffer[triangleID+2] == v1) ||
			(_indexBuffer[triangleID+1] == v1 && _indexBuffer[triangleID+2] == v2) ||
			(_indexBuffer[triangleID+1] == v2 && _indexBuffer[triangleID+2] == v1)
			))
			continue;
		
		int idE1 = -1;
		int idE2 = -1;
		int v3 = -1;
		if(_indexBuffer[triangleID] == v1 || _indexBuffer[triangleID] == v2)
			idE1 = triangleID;
		else
			v3 = triangleID;
		if(_indexBuffer[triangleID+1] == v1 || _indexBuffer[triangleID+1] == v2)
			if (idE1 != -1) 
				idE2 = triangleID+1;
			else 
				idE1 = triangleID+1;
		else
			v3 = triangleID+1;
		if(_indexBuffer[triangleID+2] == v1 || _indexBuffer[triangleID+2] == v2)
			if (idE1 != -1) 
				idE2 = triangleID+2;
			else 
				idE1 = triangleID+2;
		else
			v3 = triangleID+2;
		

		//create new vertex
		if (newIndex == -1)
		{
			CVector3f position = (_vertexBuffer[_indexBuffer[idE1]]._position + _vertexBuffer[_indexBuffer[idE2]]._position) * 0.5f;
			CVector3f normal = _vertexBuffer[_indexBuffer[idE1]]._normal;
			meshVertex newVertex(position, normal);
			newIndex = _vertexBuffer.size();
			_vertexBuffer.push_back(newVertex);

			//create new geovertex
			GeoVertex* newV = SCENE.createVertex();
			newV->setInfo(this, newIndex, position);
			_geoVertexBuffer.push_back(newV);
		}

		//create new triangles
		int saveIdE2 = _indexBuffer[idE2];
		_indexBuffer[idE2] = newIndex;

		//calculte two edges
		CVector3f e1 = _vertexBuffer[newIndex]._position - _vertexBuffer[saveIdE2]._position;
		CVector3f e2 = _vertexBuffer[_indexBuffer[v3]]._position - _vertexBuffer[saveIdE2]._position;
		
		//calculate the winding
		CVector3f n = e1.cross(e2);
		float winding = _normalPerTriangleBuffer[triangleID/3].dot(n);
		
		
		_indexBuffer.push_back(saveIdE2);
		_uvMapBuffer.push_back(CVector3f(0, 0, 0));
		if (winding <= 0)
		{
			_indexBuffer.push_back(_indexBuffer[v3]);
			_uvMapBuffer.push_back(CVector3f(0, 0, 0));
			_indexBuffer.push_back(newIndex);
			_uvMapBuffer.push_back(CVector3f(0, 0, 0));
		}
		else if (winding > 0)
		{
			_indexBuffer.push_back(newIndex);
			_uvMapBuffer.push_back(CVector3f(0, 0, 0));
			_indexBuffer.push_back(_indexBuffer[v3]);
			_uvMapBuffer.push_back(CVector3f(0, 0, 0));
		}
		_normalPerTriangleBuffer.push_back(_normalPerTriangleBuffer[triangleID/3]);
	}

	return true;
}


//delete a vertex from the mesh
void GeoMesh::deleteVertex(int vertexID)
{
	//id out if range
	if (vertexID < 0 || vertexID >= _vertexBuffer.size()) return;

	//delete the vertex in the vertex buffer
	_vertexBuffer[vertexID]._normal = CVector3f(0, 0, 0);

	//delete the triangles
	int currentID = 0;
	int size = _indexBuffer.size();
	while(currentID<size)
	{
		//if the deleted vertex is a part of the triangle, delete the triangle
		if(_indexBuffer[currentID] == vertexID || _indexBuffer[currentID+1] == vertexID ||
			_indexBuffer[currentID+2] == vertexID)
		{
			//delete the triangle
			vector<int>::iterator itFirstIndex = _indexBuffer.begin() + currentID;
			vector<int>::iterator itLastIndex = _indexBuffer.begin() + currentID+3;
			_indexBuffer.erase(itFirstIndex, itLastIndex); 

			//delete the uvmap
			vector<CVector3f>::iterator itFirstUVIndex = _uvMapBuffer.begin() + currentID;
			vector<CVector3f>::iterator itLastUVIndex = _uvMapBuffer.begin() + currentID+3;
			_uvMapBuffer.erase(itFirstUVIndex, itLastUVIndex); 

			//delete the normal
			vector<CVector3f>::iterator itNormal = _normalPerTriangleBuffer.begin() + currentID / 3;
			_normalPerTriangleBuffer.erase(itNormal);

			//calculate the size of the index buffer
			size = _indexBuffer.size();
		}
		else
		{
			currentID += 3;
		}
	}

	//calculate the new bounding box
	calculateAABB();
}

//merge two vertices
bool GeoMesh::mergeVertices(int v1, int v2)
{
	//calculate the new position of the point
	_vertexBuffer[v2]._position = (_vertexBuffer[v1]._position + _vertexBuffer[v2]._position) * 0.5f;
	_geoVertexBuffer[v2]->setTranslate(_vertexBuffer[v2]._position);
	//erase v1
	_vertexBuffer[v1]._normal = CVector3f(0, 0, 0);

	//erase v1 from the index buffer
	int i = 0;
	int size = _indexBuffer.size();
	while(i < size)
	{
		bool v1Present = false;
		if(_indexBuffer[i] == v1 || _indexBuffer[i+1] == v1 || _indexBuffer[i+2] == v1) v1Present = true;
		bool v2Present = false;
		if(_indexBuffer[i] == v2 || _indexBuffer[i+1] == v2 || _indexBuffer[i+2] == v2) v2Present = true;

		//delete the triangle
		if(v1Present && v2Present)
		{
			//delete the triangle
			vector<int>::iterator itFirstIndex = _indexBuffer.begin() + i;
			vector<int>::iterator itLastIndex = _indexBuffer.begin() + i+3;
			_indexBuffer.erase(itFirstIndex, itLastIndex); 

			//delete the uvmap
			//delete the uvmap
			vector<CVector3f>::iterator itFirstUVIndex = _uvMapBuffer.begin() + i;
			vector<CVector3f>::iterator itLastUVIndex = _uvMapBuffer.begin() + i+3;
			_uvMapBuffer.erase(itFirstUVIndex, itLastUVIndex); 

			//delete the normal
			vector<CVector3f>::iterator itNormal = _normalPerTriangleBuffer.begin() + i / 3;
			_normalPerTriangleBuffer.erase(itNormal);

			//calculate the size of the index buffer
			size = _indexBuffer.size();
		}
		else if (v1Present)
		{
			if(_indexBuffer[i] == v1) _indexBuffer[i] = v2;
			if(_indexBuffer[i+1] == v1) _indexBuffer[i+1] = v2;
			if(_indexBuffer[i+2] == v1) _indexBuffer[i+2] = v2;
			i+=3;
		}
		else 
		{
			i+=3;
		}
	}
	return true;

}

//delete all the geovertex of the mesh
void GeoMesh::deleteAllGeoVertex()
{
	for(vector<GeoVertex*>::iterator i = _geoVertexBuffer.begin(); i != _geoVertexBuffer.end(); i++)
	{
		SCENE.deletePrimitive(*i);
		(*i) = 0;
	}
}
//calculate normals of the triangles containing the point identifying with vertexID
void GeoMesh::calculateTrianglesNormal(int vertexID)
{
	//loop through every triangles
	for(int i = 0; i < _indexBuffer.size(); i+=3)
	{
		//the vertex is not a member of this triangle
		if ( _indexBuffer[i] != vertexID && _indexBuffer[i+1] != vertexID && _indexBuffer[i+2] != vertexID)
			continue;

		//the vertex is a member of the triangle
		CVector3f edge1 = _vertexBuffer[_indexBuffer[i+1]]._position - _vertexBuffer[_indexBuffer[i]]._position;
		CVector3f edge2 = _vertexBuffer[_indexBuffer[i+2]]._position - _vertexBuffer[_indexBuffer[i]]._position;

		CVector3f n = edge1.cross(edge2);
		n.normalize();
		_normalPerTriangleBuffer[i/3] = n;
	}
}

//update the AABB when the vertex vertexID has been moved
void GeoMesh::updateAABB(int vertexID)
{
	meshVertex m = _vertexBuffer[vertexID];

	const float offset = 0.1f;
	if (_aabb[0] > m._position.x) _aabb[0] = m._position.x - offset;
	if (_aabb[1] < m._position.x) _aabb[1] = m._position.x + offset;

	if (_aabb[2] > m._position.y) _aabb[2] = m._position.y - offset;
	if (_aabb[3] < m._position.y) _aabb[3] = m._position.y + offset;

	if (_aabb[4] > m._position.z) _aabb[4] = m._position.z - offset;
	if (_aabb[5] < m._position.z) _aabb[5] = m._position.z + offset;

	_translateMark = CVector3f(0, _aabb[3] + 0.2f, 0);
	_rotationMarkRadius = _aabb[1] - _aabb[0] + 0.2f;
}

//calculate the normals per vertex
void GeoMesh::calculateNormalPerVertex()
{
	int nbTriangles = _indexBuffer.size() / 3;
	

	//loop through every vertex
	for(int idVertex = 0; idVertex < _vertexBuffer.size(); idVertex++)
	{
		_vertexBuffer[idVertex]._normal = CVector3f(0, 0, 0);
		int nbTriangles = 0;

		//loop through every triangles
		for(int idTriangles = 0; idTriangles < nbTriangles; idTriangles++)
		{
			//check if the vertex is a part of the triangle
			int id = idTriangles * 3;
			if (_indexBuffer[id] != idVertex && _indexBuffer[id+1] != idVertex && _indexBuffer[id+2] != idVertex)
				continue;

			//calculate the sum of the normals
			_vertexBuffer[idVertex]._normal += _normalPerTriangleBuffer[idTriangles];
			nbTriangles++;
		}

		//divide the normals per the number of triangle (to get the average)
		if(nbTriangles != 0) _vertexBuffer[idVertex]._normal * (1/nbTriangles);
	}
}
//return the number of triangle in the mesh
int GeoMesh::getTrianglesCount()const
{
	return _indexBuffer.size() / 3;
}

//get the number of triangles owning a vertex
int GeoMesh::getTrianglesCount(int vertexID)const
{
	if (vertexID < 0 || vertexID >= _vertexBuffer.size()) return 0;

	int count = 0;
	//for(vector<int>::iterator i = _indexBuffer.begin(); i != _indexBuffer.end(); i++)
	for(int i = 0; i < _indexBuffer.size(); i++)
		if (_indexBuffer[i]==vertexID) count++;

	return count;
}

//tell the mesh to draw a triangle
void GeoMesh::setDrawSpecialTriangle(int vertexID, int triangleCount)
{
	_triangleDrawVertexID = vertexID;
	_triangleDrawTriangleCount = triangleCount;
}

//get the uv map of a vertex in a specific triangle
CVector3f GeoMesh::getUVMap(int vertexID, int triangleCount)const
{
	int countTriangle = 0;
	for(int i = 0; i < _indexBuffer.size(); i+=3)
	{
		int id = -1;
		if(_indexBuffer[i] == vertexID) id = i;
		if (_indexBuffer[i+1] == vertexID) id = i+1;
		if (_indexBuffer[i+2] == vertexID) id = i+2;
		if(id == -1) continue;
		
		if(countTriangle == triangleCount)
		{
			return _uvMapBuffer[id];
		}
		else
		{
			countTriangle ++;
		}
	}

	return CVector3f();
}

//set the uv map of a vertex in a specific triangle
void GeoMesh::setUVMap(int vertexID, int triangleCount, const CVector3f& uv)
{
	int countTriangle = 0;
	for(int i = 0; i < _indexBuffer.size(); i+=3)
	{
		int id = -1;
		if(_indexBuffer[i] == vertexID) id = i;
		if (_indexBuffer[i+1] == vertexID) id = i+1;
		if (_indexBuffer[i+2] == vertexID) id = i+2;
		if(id == -1) continue;
		
		if(countTriangle == triangleCount)
		{
			_uvMapBuffer[id] = uv;
			return;
		}
		else
		{
			countTriangle ++;
		}
	}
}

//create all the geovertex corresponding to the mesh
void GeoMesh::createAllGeoVertex()
{
	for(int i = 0; i < _vertexBuffer.size(); i++)
	{
			//create new geovertex
			GeoVertex* newV = SCENE.createVertex();
			newV->setInfo(this, i, _vertexBuffer[i]._position);
			_geoVertexBuffer.push_back(newV);
	}

}

//draw the selected triangle (if selected)
void GeoMesh::drawSelectedTriangle()
{
	//nothing to draw
	if (_triangleDrawVertexID < 0) return;

	int countTriangle = 0;
	for(int i = 0; i < _indexBuffer.size(); i+=3)
	{
		if(_indexBuffer[i] == _triangleDrawVertexID || _indexBuffer[i+1] == _triangleDrawVertexID ||
			_indexBuffer[i+2] == _triangleDrawVertexID)
		{
			if(countTriangle == _triangleDrawTriangleCount)
			{
				//draw the triangle
				glDisable(GL_LIGHTING);
				glColor3f(1, 1, 1);
				glLineWidth(3);
				glBegin(GL_LINE_STRIP);
					glVertex3f(_vertexBuffer[_indexBuffer[i]]._position.x,
						_vertexBuffer[_indexBuffer[i]]._position.y,
						_vertexBuffer[_indexBuffer[i]]._position.z);

					glVertex3f(_vertexBuffer[_indexBuffer[i+1]]._position.x,
						_vertexBuffer[_indexBuffer[i+1]]._position.y,
						_vertexBuffer[_indexBuffer[i+1]]._position.z);

					glVertex3f(_vertexBuffer[_indexBuffer[i+2]]._position.x,
						_vertexBuffer[_indexBuffer[i+2]]._position.y,
						_vertexBuffer[_indexBuffer[i+2]]._position.z);

					glVertex3f(_vertexBuffer[_indexBuffer[i]]._position.x,
						_vertexBuffer[_indexBuffer[i]]._position.y,
						_vertexBuffer[_indexBuffer[i]]._position.z);
				glEnd();
				glEnable(GL_LIGHTING);
				return;
			}
			else
				countTriangle++;
		}
	}

	
}